"""
提供一个系统时间同步

date: 2025/8/20
author: SiHeng Tang
file: sys_time_sync.py
copyright(c) DFSA Eastern Software
此程序不能提供任何担保 WITHOUT WARRANTY OF ANY KIND
"""
import logging
import subprocess
import time
from copy import deepcopy

from async_sche import TaskWrapper, BaseTaskGen, ExitGenerationError
from mengji import Vehicle
from mod_loader import ConfigHandler
from task_element import DataEndpoint

logger = logging.getLogger(__name__)
handler = ConfigHandler(__name__)

DEFAULT_CONFIG = {
    "label": "sys_time_sync",
    "apply_to_host": 0,
    "max_time_diff_sec": 60,
    "check_time_per_sec": 10,
    "display_formatter": "%F %T %Z"
}

YEAR_2000_UTC_SEC = 946684800.0


class SysTimeSync(BaseTaskGen):
    """
    机载时间同步，如果机载计算机没有独立 RTC，自动驾驶仪通过 GPS 获得的准确授时可能与机载计算机时钟出现差异，
    此类检查时钟是否在许可偏差内并将 GPS 时间同步到机载计算机上
    """

    def __init__(self, cfg: dict):
        super().__init__(priority=TaskWrapper.IDLE_PRIORITY + 10)
        self._config = cfg
        self._apply_to_host = self._config["apply_to_host"]
        self._max_time_diff = self._config["max_time_diff_sec"]
        self._time_display_formatter = self._config["display_formatter"]

        self._mav_unix_epoch = 0.0
        self.recv_mav_time_ep = DataEndpoint()

        self._last_check = time.time()

    def _on_gen(self):
        dp = self.recv_mav_time_ep.get_dp()
        mav_sys_time_load = dp.get_a("payload")
        if (not mav_sys_time_load) or ("time_unix_usec" not in mav_sys_time_load.keys()):
            raise ExitGenerationError()
        mav_epoch = mav_sys_time_load["time_unix_usec"]
        if mav_epoch < YEAR_2000_UTC_SEC:
            raise ExitGenerationError()

        self._mav_unix_epoch = mav_epoch

        if (time.time() - self._last_check) < self._config["check_time_per_sec"]:
            raise ExitGenerationError()
        else:
            self._last_check = time.time()

    async def _func(self):
        # 检查时间差，确定是否需要更新时间
        logger.debug(f"system time now {time.strftime(self._time_display_formatter, time.localtime(time.time()))} "
                     f"mav gps input {time.strftime(self._time_display_formatter, time.localtime(self._mav_unix_epoch))} "
                     f"difference {time.time() - self._mav_unix_epoch=}")

        if abs(time.time() - self._mav_unix_epoch) > self._max_time_diff:
            logger.warning(
                f"requests time change to "
                f"{time.strftime(self._time_display_formatter, time.localtime(self._mav_unix_epoch))}")

            if self._apply_to_host:
                cmd = ["date", "-s", "@{}".format(self._mav_unix_epoch)]

                try:
                    subprocess.run(cmd, check=True)
                    print(f"successfully set time to "
                          f"{time.strftime(self._time_display_formatter, time.localtime(self._mav_unix_epoch))}")
                except subprocess.CalledProcessError as e:
                    pass

    def _on_exit(self):
        self.recv_mav_time_ep = None

    ########################
    # 访问接口
    ########################
    def get_mav_system_time_str(self, **kwargs):
        """
        获取一个飞行器时间，一定是本地化时间戳字符串，通常来源于 GPS
        :param kwargs: 可选的指定格式化字符串 (不推荐)，使用 formatter 指定
        :return: 时间字符串，如果可用，不可用返回 None
        """
        if self._mav_unix_epoch < YEAR_2000_UTC_SEC:
            return None

        formatter = kwargs["formatter"] if "formatter" in kwargs.keys() else self._time_display_formatter
        return time.strftime(formatter, time.localtime(self._mav_unix_epoch))


@handler.add_handler("virtual_bus:sys_time_sync")
def load_config(veh: Vehicle, cfg_section: dict):
    logger.debug(f"system time sync service load config {cfg_section}")

    cfg = deepcopy(DEFAULT_CONFIG)
    cfg.update(cfg_section)

    veh.reg_part(cfg["label"], SysTimeSync(cfg), is_sche=True)
